package org.dromara.web.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.dromara.common.core.domain.model.XcxLoginBody;
import org.dromara.common.core.domain.model.XcxLoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.bo.XcxUserBo;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.TalentUserVo;
import org.dromara.system.domain.vo.XcxUserVo;
import org.dromara.system.service.ISysPermissionService;
import org.dromara.system.service.ITalentUserService;
import org.dromara.system.service.IXcxUserService;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;

import static org.dromara.common.core.constant.Constants.XCX_DEFAULT_NAME;
import static org.dromara.common.core.enums.UserType.APP_USER;

/**
 * 小程序认证策略
 *
 * @author Michelle.Chung
 */
@Slf4j
@Service("xcx" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor
public class XcxAuthStrategy implements IAuthStrategy {

    private final SysLoginService loginService;
    private final WxMaService wxMaService;
    private final IXcxUserService xcxUserService;
    private final ISysPermissionService permissionService;
    private final ITalentUserService talentUserService;


    @Override
    public LoginVo login(String body, SysClientVo client) {
        XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class);
        // xcxCode 为 小程序调用 wx.login 授权后获取
        String xcxCode = loginBody.getXcxCode();

        String openid, unionId;

        try {
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(xcxCode);
            openid = sessionInfo.getOpenid();
        } catch (WxErrorException wxErrorException) {
            throw new ServiceException(wxErrorException.getMessage());

        }
        XcxLoginUser xcxLoginUser = buildLoginUser(loginBody, client, openid);

        SaLoginParameter model = new SaLoginParameter();
        model.setDeviceType(client.getDeviceType());
        // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
        // 例如: 后台用户30分钟过期 app用户1天过期
        model.setTimeout(client.getTimeout());
        model.setActiveTimeout(client.getActiveTimeout());
        model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
        // 生成token
        LoginHelper.login(xcxLoginUser, model);

        LoginVo loginVo = new LoginVo();
        loginVo.setAccessToken(StpUtil.getTokenValue());
        loginVo.setExpireIn(StpUtil.getTokenTimeout());
        loginVo.setClientId(client.getClientId());
        loginVo.setOpenid(openid);
        return loginVo;
    }

    private XcxLoginUser buildLoginUser(XcxLoginBody loginBody, SysClientVo client, String openid) {
        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
        XcxUserVo user = loadUserByOpenid(loginBody, openid);
        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        XcxLoginUser xcxLoginUser = new XcxLoginUser();
        xcxLoginUser.setMenuPermission(new HashSet<>());
        xcxLoginUser.setRolePermission(new HashSet<>());
        xcxLoginUser.setUserId(user.getUserId());
        xcxLoginUser.setUsername(user.getUserName());
        xcxLoginUser.setUserType(user.getXcxUserType());
        xcxLoginUser.setClientKey(client.getClientKey());
        xcxLoginUser.setDeviceType(client.getDeviceType());
        xcxLoginUser.setOpenid(openid);
        if (user.getSysUserId() != null) {
            xcxLoginUser.setMenuPermission(permissionService.getMenuPermission(user.getSysUserId()));
            xcxLoginUser.setRolePermission(permissionService.getRolePermission(user.getSysUserId()));
        }

        return xcxLoginUser;
    }

    private XcxUserVo loadUserByOpenid(XcxLoginBody loginBody, String openid) {
        XcxUserVo xcxUserVo = xcxUserService.queryByOpenId(openid);
        if (ObjectUtil.isNull(xcxUserVo)) {
            log.info("登录用户：{} 不存在.", openid);
            XcxUserBo xcxUser = new XcxUserBo();
            xcxUser.setOpenId(openid);
            xcxUser.setUserName(XCX_DEFAULT_NAME);
            String phoneNumber = loginBody.getPhoneNumber();
            List<TalentUserVo> talentUserVos = talentUserService.queryByPhoneNumber(loginBody.getPhoneNumber());
            if (ObjectUtil.isNotNull(talentUserVos)) {
                TalentUserVo talentUserVo = talentUserVos.get(0);
                xcxUser.setUserName(talentUserVo.getUserName());
                xcxUser.setSex(talentUserVo.getSex());
            }
            xcxUser.setPhonenumber(phoneNumber);
            xcxUser.setXcxUserType(APP_USER.getUserType());
            xcxUserService.insertByBo(xcxUser);
            return xcxUserService.queryById(xcxUser.getUserId());
        }
        return xcxUserVo;
    }

}
